package pt.compflow.storage;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import pt.compflow.flowontology.model.FLOWO;
import pt.compflow.flowontology.model.FlowOntologyModel;
import pt.compflow.flowontology.model.FlowOntologyModelFactory;

import com.hp.hpl.jena.graph.Graph;
import com.hp.hpl.jena.graph.compose.MultiUnion;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.reasoner.Reasoner;
import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasoner;
import com.hp.hpl.jena.reasoner.rulesys.Rule;
import com.hp.hpl.jena.sparql.vocabulary.FOAF;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;

public abstract class TripleStoreConnectionBase implements TripleStoreConnection {
		
	protected Properties config;
	protected Map<String, String> prefixMap;
		
	protected TripleStoreConnectionBase() {
		prefixMap = new HashMap<String, String>();
		prefixMap.put("cflow", FLOWO.getURI());
		prefixMap.put("foaf", FOAF.getURI());
		prefixMap.put("rdf", RDF.getURI());
		prefixMap.put("rdfs", RDFS.getURI());
	}
	
	protected TripleStoreConnectionBase(Properties config) {
		this();
		this.config = config;
	}
	
	/**
	 * Creates a FlowOntologyModel with a UnionGraph that contains the individualGraph and the
	 * ontologies graph (withe the ontologies specified in the config file)
	 *  
	 * @param individualGraph - the main modifiable graph to be wrapped by the FlowOntologyModel
	 * @return the FlowOntologyModel with the ontology graph and the individualGraph as base graph 
	 */
	protected FlowOntologyModel getFullModel(Graph individualGraph) {
		// create a default in-memory ont model
		Model ontModel = ModelFactory.createDefaultModel();
		
		if(config != null && config.containsKey("ontologies")) {
			String[] ontologies = config.getProperty("ontologies").split(";");
	
			// read all ontologies specified in the TripleStore config file to the ont model
			for (int i = 0; i < ontologies.length; i++) {
				ontModel.read(ontologies[i], null);
			}
		}
		
		// use reasoning?
		OntModelSpec ontModelSpec = OntModelSpec.OWL_DL_MEM;//OWL_DL_MEM_RDFS_INF;
		
		// if a rule file is specified, include the rules in the reasoner
		if(config != null && config.containsKey("ontologyRuleFile")) {
			Reasoner reasoner = new GenericRuleReasoner(Rule.rulesFromURL(config.getProperty("ontologyRuleFile")));
	        reasoner = reasoner.bindSchema(ontModel);
	        ontModelSpec.setReasoner(reasoner);
		}
        
		// build a graph that represents the union of both the TripleStore and ontology graphs
        MultiUnion unionGraph = new MultiUnion();
        unionGraph.addGraph(individualGraph);
        unionGraph.addGraph(ontModel.getGraph());
        // the base graph (the one over which modifications will be performed) is the TripleStore graph
        unionGraph.setBaseGraph(individualGraph);
        
        // set reasoning and create full model from the union graph
        OntModel fullOntModel = ModelFactory.createOntologyModel(ontModelSpec, ModelFactory.createModelForGraph(unionGraph));     
        FlowOntologyModel fullModel = FlowOntologyModelFactory.createModelForGraph(fullOntModel.getGraph());
        fullModel.setNsPrefixes(prefixMap);
        return fullModel;
	}
	
	@Override
	public FlowOntologyModel connectModel() {
		FlowOntologyModel model = FlowOntologyModelFactory.createModelForGraph(connectGraph());
		model.setNsPrefixes(prefixMap);
		return model;
	}
	
	@Override
	public FlowOntologyModel connectNamedModel(String iri) {
		FlowOntologyModel model = FlowOntologyModelFactory.createModelForGraph(connectNamedGraph(iri));
		model.setNsPrefixes(prefixMap);
		return model;
	}
//	
//	@Override
//	public FlowOntologyModel connectFullModel() {
//		return getFullModel(connectGraph());
//	}
//	
//	@Override
//	public FlowOntologyModel connectFullNamedModel(String iri) {
//		return getFullModel(connectNamedGraph(iri));
//	}
	
	@Override
	public OntModel connectNamedOntModel(String iri) {
		return ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM, connectNamedModel(iri));
	}

	public Properties getConfig() {
		return config;
	}

	public void setConfig(Properties config) {
		this.config = config;
	}	
}